package com.yf.modules.security.service.impl;

import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yf.Utils.RedisUtils;
import com.yf.Utils.RsaUtils;
import com.yf.config.rsa.RsaProperties;
import com.yf.configuration.SecurityProperties;
import com.yf.domain.security.User;
import com.yf.dao.UserMapper;
import com.yf.modules.security.model.convert.UserConvert;
import com.yf.modules.security.model.dto.AuthUserDto;
import com.yf.modules.security.model.dto.JwtUserDto;
import com.yf.modules.security.service.OnlineUserService;
import com.yf.modules.security.service.TokenProvider;
import com.yf.modules.security.service.api.AuthService;
import com.yf.modules.security.model.dto.UserDto;
import com.yf.response.exceptions.BusinessException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author chentianwei
 * @date 2023/5/9 13:26
 * @description Auth impl
 */
@Service
@Slf4j
public class AuthServiceImpl implements AuthService {

    private final UserMapper userMapper;
    private final OnlineUserService onlineUserService;
    private final AuthenticationManagerBuilder authenticationManagerBuilder;
    private final TokenProvider tokenProvider;
    private final SecurityProperties properties;
    private final RsaProperties rsaProperties;
    private final RedisUtils redisUtils;

    public AuthServiceImpl(UserMapper userMapper, OnlineUserService onlineUserService,
                           AuthenticationManagerBuilder authenticationManagerBuilder,
                           TokenProvider tokenProvider,
                           SecurityProperties properties,
                           RsaProperties rsaProperties,
                           RedisUtils redisUtils) {
        this.userMapper = userMapper;
        this.onlineUserService = onlineUserService;
        this.authenticationManagerBuilder = authenticationManagerBuilder;
        this.tokenProvider = tokenProvider;
        this.properties = properties;
        this.rsaProperties = rsaProperties;
        this.redisUtils = redisUtils;
    }


    @Override
    public Map<String, Object> login(AuthUserDto authUser) {
        //1.对RSA私钥密码解密
        String password = "";
        try {
            password = RsaUtils.decryptByPrivateKey(rsaProperties.getPrivateKey(), authUser.getPassword());
        } catch (Exception e) {
            e.printStackTrace();
        }

        //2.发放Auth
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(authUser.getUsername(), password);
        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String token = tokenProvider.createToken(authentication);

        final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal();

        //3.把token发放并带回
        Map<String, Object> authInfo = new HashMap<>(2) {{
            put("token", properties.getTokenStartWith() + token);
            put("user", jwtUserDto);
        }};
        //4.保存token信息
        onlineUserService.UserCacheSave(jwtUserDto, token, null);
        return authInfo;
    }

    @Override
    public void logout(HttpServletRequest request) {
        String token = tokenProvider.getToken(request);
        redisUtils.del(properties.getOnlineKey() + token);
    }

    @Override
    public UserDto findByUserName(String userName) {

        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(User::getUserName, userName);
        User user = userMapper.selectOne(wrapper);

        if (Objects.isNull(user)) {
            throw new BusinessException("用户" + userName + "不存在");
        }
        if (BooleanUtil.isFalse(user.getIsEnable())) {
            throw new BusinessException("用户" + userName + "未激活，请联系管理员激活");
        }

        return UserConvert.convertEntityToModel(user);
    }

    /**
     * 判定用户是否有自定义的权限操作
     *
     * @param permissionCode 权限操作符
     * @return 布尔值
     */
    @Override
    public Boolean hasPermission(String permissionCode) {
        return null;
    }
}
